package com.winning.sx.microframework.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.winning.sx.microframework.common.constant.GenericApiConstant;
import com.winning.sx.microframework.common.support.DataMap;
import com.winning.sx.microframework.common.support.Ret;
import com.winning.sx.microframework.common.util.Constains;
import com.winning.sx.microframework.dao.sysmanage.GenericApiManageDao;
import com.winning.sx.microframework.model.exception.CustomException;
import com.winning.sx.microframework.model.genericapi.GenericApiInterfaceConfig;
import com.winning.sx.microframework.model.genericapi.GenericApiInterfaceInfo;
import com.winning.sx.microframework.model.genericapi.GenericApiInterfaceLog;
import com.winning.sx.microframework.plugins.wx.WxConfig;
import com.winning.sx.microframework.plugins.wx.WxUtil;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wangj_envy
 * @date 2019年6月5日13:17:27
 */
@Service
public class GenericApiService {

    @Autowired
    private GenericApiManageDao genericApiManageDao;

    /**
     * 入口
     *
     * @param data
     * @return
     */
    public Ret send(String data, String requestIP) {
        Map<String, Object> paramMap;
        Ret response = null;
        GenericApiInterfaceLog logMap = new GenericApiInterfaceLog(data, requestIP);//日志

        try {
            Map<String, Object> retData = null;
            if (data != null) {
                paramMap = DataMap.transfrom(data);
                logMap.setParamMap(paramMap);
                retData = onService(logMap);
                response = Ret.success(retData);
                logMap.setLogLevel("Info");
            }
        } catch (IOException e) {
            response = Ret.error("请求参数有误！", GenericApiConstant.ERROR_CODE_PARAM);
            logMap.setExceptionMessage("\"请求参数有误！\"");
        } catch (CustomException e) {
            response = Ret.error(e.getErrorMessage(), e.getErrorCode());
            logMap.setExceptionMessage(e.toString());
        } catch (Exception e) {
            e.printStackTrace();
            response = Ret.error(e.getMessage(), GenericApiConstant.ERROR_CODE_VALID_OTHER);
            logMap.setExceptionMessage(e.toString());
        } finally {
            try {
                logMap.caculateTime();
                logMap.setReturnContent(response.toString());
                recordLog(logMap);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return response;
        }
    }

    /**
     * 接口服务
     *
     * @param logMap
     * @return
     * @throws CustomException
     */
    public Map onService(GenericApiInterfaceLog logMap) throws CustomException {
        Map map = logMap.getParamMap();
        String inter = (String) map.get(GenericApiConstant.INTERFACE_CODE);
        String serverName = (String) map.get(GenericApiConstant.SERVER_NAME);

        switch (serverName) {

            case GenericApiConstant.SERVER_NAME_WX:

                if (!WxConfig.runState) {
                    throw new CustomException(GenericApiConstant.ERROR_CODE_SERVER, "服务器无服务");
                }

                Map interFaceWxConfig = (Map) WxConfig.api.get(inter + "Config");
                List<GenericApiInterfaceConfig> proptiesWx = (List<GenericApiInterfaceConfig>) WxConfig.api.get(inter);
                if (interFaceWxConfig == null || proptiesWx == null) {
                    throw new CustomException(GenericApiConstant.ERROR_CODE_INTERFACE, "接口无服务");
                }
                if (!Constains.STATE_NORMAL.equals(interFaceWxConfig.get("state"))) {
                    throw new CustomException(GenericApiConstant.ERROR_CODE_INTERFACE, "接口无服务");
                }

                GenericApiInterfaceInfo apiInterfaceInfoWx = new GenericApiInterfaceInfo();
                apiInterfaceInfoWx.setId(Integer.parseInt(interFaceWxConfig.get("id").toString()));
                apiInterfaceInfoWx.setName(interFaceWxConfig.get("name").toString());
                apiInterfaceInfoWx.setCurrentPattern(interFaceWxConfig.get("currentPattern").toString());
                logMap.recordInterfaceInfo(apiInterfaceInfoWx);//记录接口信息

                Map paramForSendWx = validation(proptiesWx, map);
                Map retDataWx = exec(serverName, interFaceWxConfig, paramForSendWx);
                return retDataWx;

            default:
                Map retDataDefault = new HashMap();
                retDataDefault.put("msg", "读取接口配置异常");
                retDataDefault.put("code", "9999");
                return retDataDefault;

        }
    }

    /**
     * 校验
     *
     * @param propties
     * @param map
     * @return
     * @throws CustomException
     */
    private Map validation(List<GenericApiInterfaceConfig> propties, Map map) throws CustomException {
        Map paramForSend = new HashedMap();
        //validation
        //may thorw new CustomExcepotion(-200,${xxx}"参数校验xxx不通过！")
        for (GenericApiInterfaceConfig config : propties) {
            Object validSuccessParam = config.valid(map);
            paramForSend.put(config.getCode(), validSuccessParam);
        }
        return paramForSend;
    }

    /**
     * 执行测试模拟接口
     *
     * @param apiInterfaceModel
     * @return
     */
    private Map execMock(GenericApiInterfaceInfo apiInterfaceModel) throws CustomException {
//        String url = apiInterfaceModel.url();
        Map retData = sendForMock(apiInterfaceModel);
        return retData;
    }


    /**
     * 执行
     *
     * @param apiServer
     * @param paramForSend
     * @return
     */
    private Map exec(String serverName, Map apiServer, Map paramForSend) {
        Map retData = null;
        ObjectMapper objectMapper = new ObjectMapper();
        switch (serverName) {

            case GenericApiConstant
                    .SERVER_NAME_WX:
                if (Constains.INTER_MODEL_TEST.equals(apiServer.get("currentPattern").toString()))
                    retData = WxUtil.postData(apiServer.get("testURL").toString(), paramForSend);
                else if (Constains.INTER_MODEL_PRO.equals(apiServer.get("currentPattern").toString()))
                    retData = WxUtil.postData(WxConfig.baseUrl+apiServer.get("productionURL").toString(), paramForSend);
                else if (Constains.INTER_MODEL_INTEGRATE.equals(apiServer.get("currentPattern").toString()))
                    retData = WxUtil.Integrate(apiServer.get("testReturnMessage").toString());
                break;


        }
        return retData;
    }

    /**
     * 模拟实现
     *
     * @param apiInterfaceModel
     * @return
     */
    private Map sendForMock(GenericApiInterfaceInfo apiInterfaceModel) throws CustomException {
        Map<String, Object> map;
        try {
            map = DataMap.transfrom(apiInterfaceModel.getTestReturnMessage());
        } catch (IOException e) {
            throw new CustomException(GenericApiConstant.ERROR_CODE_MOCKDATA, "模拟数据格式有误！");
        }
        return map;
    }


    /**
     * 日志
     *
     * @param logMap
     */
    public void recordLog(GenericApiInterfaceLog logMap) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        genericApiManageDao.recordLog(logMap);
    }

    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
